package framework;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

import javax.naming.NamingException;

import org.testng.Assert;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.remote.RemoteWebDriver;
import org.openqa.selenium.support.ui.ExpectedCondition;
import org.openqa.selenium.support.ui.WebDriverWait;

/**
 * Основной класс для доступа к браузеру, расширяющий возможности стандартного
 * DefaultSelenium
 */
public class Browser {

    // имя файла с настройками Selenium RC
    private static final String PROPERTIES_FILE = "selenium.properties";

    // browsers
    private static Browser instance = null;
    private static RemoteWebDriver driver = null;

    public static PropertiesResourceManager props;
    // поля класса
    private static String browserURL;
    private static String apiURL;
    private static String timeoutForPageLoad;
    private static String timeoutForCondition;

    // private static String screenshotsFolder;

    // private static String speedValue;

    /**
     * Приватный конструктор (паттерн синглтон)
     */
    private Browser() {
    System.out.println("Constructing...");
    }

    public static Browser getInstance() {
    if (instance == null) {
        initProperties();
        try {
        driver = BrowserFactory.setUp(props.getProperty("browser"));
        } catch (NamingException e) {
        e.printStackTrace();
        }

        instance = new Browser();
    }
    return instance;
    }

    public void exit() {
    try {
        driver.quit();
    } catch (Exception e) {
    }
    instance = null;
    }

    public String getTimeoutForCondition() {
    return timeoutForCondition;
    }

    public String getTimeoutForPageLoad() {
    return timeoutForPageLoad;
    }

    public long getTimeoutForConditionLong() {
    return Long.parseLong(timeoutForCondition);
    }

    public long getTimeoutForPageLoadLong() {
    return Long.parseLong(timeoutForPageLoad);
    }

    public String getStartBrowserURL() {
    return browserURL;
    }

    public String getApiURL() {
    return apiURL;
    }

    /**
     * Инициализация основных параметров класса (настройка Selenium и Watij)
     */
    private static void initProperties() {

    // фикс проблемы с Watij на последних версиях IE
    /*
     * System.setProperty("ie_version", "7"); ie = new IE();
     */
    props = new PropertiesResourceManager(
            PROPERTIES_FILE, 
            System.getenv().get("PLATFORMPROPS"));
    // speedValue = props.getProperty("speedValue");
    timeoutForPageLoad = props.getProperty("defaultPageLoadTimeout");
    timeoutForCondition = props.getProperty("defaultConditionTimeout");
    browserURL = props.getProperty("urlLoginPage");
    apiURL = props.getProperty("apiPage");
    // screenshotsFolder = System.getProperty("screenshotsFolder",
    // DEFAULT_SCREENSHOTS_FOLDER);
    // if (!screenshotsFolder.matches("^\\\\.*")) {
    // File f = new File(screenshotsFolder);
    // f.mkdirs();
    // }
    }

    public void waitForPageToLoad() {
    try {
        Thread.sleep(1000);
    } catch (InterruptedException e1) {
        e1.printStackTrace();
    }
    Future<?> future = null;
    ExecutorService executor = null;

    try {
        executor = Executors.newFixedThreadPool(1);
        future = executor.submit(new Runnable() {
        @Override
        public void run() {
            boolean threadResult = false;
            if (!(instance instanceof JavascriptExecutor)) {
            threadResult = true;
            }
            while (!threadResult) {
            Object result = ((JavascriptExecutor) instance)
                .executeScript(
                        "return document['readyState'] ? 'complete'"
                      + "== document.readyState : true");
            if (result != null 
             && result instanceof Boolean 
             && (Boolean) result) {
                threadResult = true;
            }
            }
        }
        });
        future.get(getTimeoutForPageLoadLong(), TimeUnit.SECONDS);
    } catch (Exception e) {
        Logger.getInstance().error(
                "can't wait until page load is complete: timed out");
    } finally {
        future.cancel(true);
        executor.shutdown();
    }
    }

    public void waitForNewWindow(int prevWndCount) {
    final int wndCount = prevWndCount;
    WebDriverWait wait = new WebDriverWait(driver, 
            Long.parseLong(instance.getTimeoutForCondition()));
    try {
        wait.until((ExpectedCondition<Boolean>) 
                new ExpectedCondition<Boolean>() {
        public Boolean apply(WebDriver d) {
            return d.getWindowHandles().size() > wndCount;
        }
        });
    } catch (Exception e) {
        Assert.assertTrue(false, "New window doesn't appears");
    }
    }

    public void selectPreviousWindow() {
    Object[] handles = driver.getWindowHandles().toArray();
    Assert.assertTrue(handles.length > 1, "Number of windows is too small");
    driver = (RemoteWebDriver)
            driver.switchTo().window((String) handles[handles.length - 2]);

    }

    public void openStartPage() {
    getInstance();
    driver.navigate().to(getStartBrowserURL());
    }

    public void windowMaximise() {
    getInstance();

    (driver).executeScript("if (window.screen)"
      + "{window.moveTo(0, 0);window.resizeTo(window.screen.availWidth,"
      + "window.screen.availHeight);};");


    }

    public RemoteWebDriver getDriver() {
    getInstance();
    return driver;
    }

    public void openNewPage(String url) {
    getInstance();
    driver.executeScript(String.format("window.open('%1$s','newWindow')", url));
    Object[] handles = driver.getWindowHandles().toArray();
    driver.switchTo().window((String) handles[handles.length - 1]);
    windowMaximise();
    driver.navigate().to(url);
    }
}
